package hujz.java.file_server;

import hujz.java.file_server.http.DispatcherHandler;
import hujz.java.file_server.http.FileServerInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.util.internal.logging.Slf4JLoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;
import static hujz.java.file_server.Configuration.INSTANCE;

public final class FileServer {
    private static final Logger LOGGER = LoggerFactory.getLogger(DispatcherHandler.class);

    public static String start(Configuration configuration) throws Exception {

        if (configuration != null) INSTANCE = configuration;

        // Configure SSL.
        final SslContext sslCtx;
        if (INSTANCE.isEnableSSL()) {
            SelfSignedCertificate ssc = new SelfSignedCertificate();
            sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
        } else {
            sslCtx = null;
        }

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup);
            b.channel(NioServerSocketChannel.class);
            InternalLoggerFactory.setDefaultFactory(Slf4JLoggerFactory.INSTANCE);
            b.handler(new LoggingHandler(LogLevel.INFO));
            b.handler(new ReadTimeoutHandler(90, TimeUnit.SECONDS));
            b.handler(new WriteTimeoutHandler(90, TimeUnit.SECONDS));
            b.childHandler(new FileServerInitializer(sslCtx));
            Channel ch = b.bind(INSTANCE.getPort()).sync().channel();

            System.out.println("HttpServer start successfully, use port \"" + INSTANCE.getPort() + "\".");

            ch.closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
        return null;
    }
}